﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;

namespace FangKuaiTianSe {
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window {


	public MainWindow ( ) {
		InitializeComponent ( );
		this.Loaded += new RoutedEventHandler ( this.initCanvas );
		///初始化list，将所有的点都置为可选点
		initData ( );
	}
	int[,] Martix;
	Rectangle[,] RMartix;
	List<Point> StartPoints;
	int AmountOfBlock;
	List<List<Point>> RectArray ;
	int[,] Adjacent;
	private void initCanvas ( object sender, RoutedEventArgs e ) {
		RMartix = new Rectangle[100, 100];
		for (int i = 0; i < 100; i++) {
			for (int j = 0; j < 100; j++) {
				Rectangle r = new Rectangle ( );
				r.Width = PaintCanva.ActualWidth / 100 ;
				r.Height = PaintCanva.ActualHeight / 100;
				r.SetValue ( Canvas.TopProperty, i * r.Height );
				r.SetValue ( Canvas.LeftProperty, j * r.Width );
				PaintCanva.Children.Add ( r );
				RMartix[i, j] = r;
				r.Fill = new SolidColorBrush ( Colors.White );
			}
		}
	}


	public void initData (  ) {
		Martix = new int[100, 100];
		StartPoints = new List<Point> ( );
		AmountOfBlock = 0;
		RectArray = new List<List<Point>> ( );

		for (int i = 0; i < 100; i++) {
			for (int j = 0; j < 100; j++) {
				StartPoints.Add ( new Point ( i, j ) );
			}
		}
	}


	public  int GetRandomSeed ( ) {
		byte[] bytes = new byte[4];
		System.Security.Cryptography.RNGCryptoServiceProvider rng = new System.Security.Cryptography.RNGCryptoServiceProvider ( );
		rng.GetBytes ( bytes );
		return BitConverter.ToInt32 ( bytes,0 );
	}

	/// <summary>
	/// 候选坐标法，生成分块矩阵
	/// </summary>
	/// <returns>返回生成是否成功</returns>
	public void BuiltRectBy1nd (int x1,int y1,int x2,int y2) {

		int minS = 500;
		int divX = new Random ( GetRandomSeed ( ) ).Next ( x1, x2 );
		int divY= new Random ( GetRandomSeed ( ) ).Next ( y1, y2 );

		///1
		if (new Random ( GetRandomSeed ( ) ).Next ( 0, 100 ) > 90 || (divX - x1) * (divY - y1) < minS) {
			AmountOfBlock++;
			RectArray.Add ( new List<Point> ( ) );
			for(int i= x1; i <= divX; i++) {
				for (int j= y1; j <= divY; j++) {
					Martix[i, j] = AmountOfBlock;
					RectArray.ElementAt ( AmountOfBlock-1 ).Add ( new Point ( i, j ) );
					//StartPoints.Remove ( StartPoints.FirstOrDefault ( Point => Point.X == i && Point.Y == j ) );
				}
			}
		} else
			BuiltRectBy1nd ( x1, y1, divX, divY );

		///2
		if (new Random ( GetRandomSeed ( ) ).Next ( 0, 100 ) > 90 || (divX-x1) * (y2-divY-1) < minS) {
			AmountOfBlock++;
			RectArray.Add ( new List<Point> ( ) );
			for (int i = x1; i <= divX; i++) {
				for (int j = divY+1; j <= y2; j++) {
					Martix[i, j] = AmountOfBlock;
					RectArray.ElementAt ( AmountOfBlock-1 ).Add ( new Point ( i, j ) );
					//StartPoints.Remove ( StartPoints.FirstOrDefault ( Point => Point.X == i && Point.Y == j ) );
				}
			}
		} else
			BuiltRectBy1nd ( x1, divY+1, divX, y2 );
		///3
		if (new Random ( GetRandomSeed ( ) ).Next ( 0, 100 ) > 90 || (x2-divX-1) * (divY-y1) < minS) {
			AmountOfBlock++;
			RectArray.Add ( new List<Point> ( ) );
			for (int i = divX+1; i <= x2; i++) {
				for (int j = y1; j <= divY; j++) {
					Martix[i, j] = AmountOfBlock;
					RectArray.ElementAt ( AmountOfBlock -1).Add ( new Point ( i, j ) );
					//StartPoints.Remove ( StartPoints.FirstOrDefault ( Point => Point.X == i && Point.Y == j ) );
				}
			}
		} else
			BuiltRectBy1nd ( divX+1, y1, x2,divY );
		///4
		if (new Random ( GetRandomSeed ( ) ).Next ( 0, 100 ) > 90 || (x2-divX-1) * (y2 - divY-1) < minS) {
			AmountOfBlock++;
			RectArray.Add ( new List<Point> ( ) );
			for (int i = divX+1; i <= x2; i++) {
				for (int j = divY + 1; j <= y2; j++) {
					Martix[i, j] = AmountOfBlock;
					RectArray.ElementAt ( AmountOfBlock -1).Add ( new Point ( i, j ) );
					//StartPoints.Remove ( StartPoints.FirstOrDefault ( Point => Point.X == i && Point.Y == j ) );
				}
			}
		} else
			BuiltRectBy1nd ( divX+1, divY+1, x2, y2 );

	}

	public void BuiltRectBy2nd ( ) {

		this.Dispatcher.Invoke ( DispatcherPriority.Normal, (ThreadStart)delegate {
			int n = (int)ChooseNumOfBlock.Value;

			for (int i = 0; i < n; i++) {
				RectArray.Add( new List<Point> ( ) ) ;

				Point point = StartPoints.ElementAt ( new Random ( GetRandomSeed ( ) ).Next ( 0, StartPoints.Count ( ) ) );
				RectArray.ElementAt(i).Add ( point );
				Martix[(int)point.X, (int)point.Y] = i+1;
				StartPoints.Remove ( point );
			}

			while(StartPoints.Count()>0) {
				int randChoose = new Random ( GetRandomSeed ( ) ).Next ( 0, n );
				foreach (Point p in RectArray.ElementAt ( randChoose )) {
					Point point = RandByPoint (p);
					if (point.X == -1)
						continue;
					else {
						RectArray.ElementAt(randChoose).Add ( point );
						Martix[(int)point.X, (int)point.Y] = randChoose + 1;
						StartPoints.Remove ( point );
						break;
					}
				}
			}
		} );
	}

	private Point RandByPoint(Point p ) {
		if (((int)p.X - 1) >= 0 && (Martix[(int)p.X - 1, (int)p.Y] == 0)) {
			return new Point ( p.X - 1, p.Y );
		}
		if (((int)p.X + 1) <= 99 && (Martix[(int)p.X + 1, (int)p.Y] == 0)) {
			return new Point ( p.X + 1, p.Y );
		}
		if (((int)p.Y - 1) >= 0 && (Martix[(int)p.X, (int)p.Y - 1] == 0)) {
			return new Point ( p.X, p.Y - 1 );
		}
		if (((int)p.Y + 1) <= 99 && (Martix[(int)p.X, (int)p.Y + 1] == 0)) {
			return new Point ( p.X, p.Y + 1 );
		}

		return new Point ( -1,-1 );
	}

	private void getAdjacent( ) {
		Adjacent = new int[RectArray.Count ( ), RectArray.Count ( )];
		for(int i=0; i< RectArray.Count ( ); i++) {
			for (int j=0; j<RectArray.ElementAt ( i ).Count ( ); j++) {
				Point p = RectArray.ElementAt ( i ).ElementAt ( j );
				if (((int)p.X - 1) >= 0 && (Martix[(int)p.X - 1, (int)p.Y] != i+1)) {
					Adjacent[i, Martix[(int)p.X - 1, (int)p.Y] - 1] = 1;
				}
				if (((int)p.X + 1) <= 99 && (Martix[(int)p.X + 1, (int)p.Y] != i + 1)) {
					Adjacent[i, Martix[(int)p.X + 1, (int)p.Y] - 1] = 1;
				}
				if (((int)p.Y - 1) >= 0 && (Martix[(int)p.X, (int)p.Y - 1] != i + 1)) {
					Adjacent[i, Martix[(int)p.X, (int)p.Y - 1] - 1] = 1;
				}
				if (((int)p.Y + 1) <= 99 && (Martix[(int)p.X, (int)p.Y + 1] != i + 1)) {
					Adjacent[i, Martix[(int)p.X, (int)p.Y + 1] - 1] = 1;
				}
			}
		}

	}



	private void FillWithFourColor ( ) {
		int[,] ColorMartix = new int[100, 100];

		Dispatcher.BeginInvoke ( new Action ( ( ) => {
			showLoad.Content = "正在计算,请稍后...";
			showLoad.Foreground = new SolidColorBrush( Colors.Red ) ;
		} ) );

		int[] Record = new int[RectArray.Count ( )];
		int m = 0, n = 1;

		while (m < RectArray.Count ( )) {

			while (n <= 4 && m < RectArray.Count ( )) {
				int k;
				for (k=0; k< m; k++) {
					if (Adjacent[m, k] == 1 && Record[k] == n)
						break;
				}
				if (k < m)
					n++;
				else {
					Record[m] = n;
					m++;
					n = 1;
				}
			}
			if (n > 4) {
				m--;
				n = Record[m] + 1;
			}
		}


		Dispatcher.BeginInvoke ( new Action ( ( ) => {
			showLoad.Content = "计算完毕，正在演示...";
			showLoad.Foreground = new SolidColorBrush ( Colors.Green );
		} ) );
		///为即将渲染的的矩阵渲染
		for (int i = 0; i < RectArray.Count ( ); i++) {
			//次线程休眠1秒
			Thread.Sleep (200);
			//Thread t=new Thread ( () =>{
			Dispatcher.Invoke ( new Action ( ( ) => {
				drawColorMartix ( ColorMartix );
			} ));
			//} );
			//t.Start ( );

			foreach (Point p in RectArray.ElementAt ( i )) {
				ColorMartix[(int)p.X, (int)p.Y] = Record[i];
			}
		}
	}

	private void drawColorMartix ( int[,] ColorMartix ) {
		Dispatcher.BeginInvoke ( new Action ( ( ) => {
			for (int i = 0; i < 100; i++) {
				for (int j = 0; j < 100; j++) {
					switch (ColorMartix[i, j]) {
					case 0:
						RMartix[i, j].Fill = new SolidColorBrush ( Colors.White );
						break;
					case 1:
						RMartix[i, j].Fill = new SolidColorBrush ( Colors.Yellow );
						break;
					case 2:
						RMartix[i, j].Fill = new SolidColorBrush ( Colors.Green );
						break;
					case 3:
						RMartix[i, j].Fill = new SolidColorBrush ( Colors.Blue );
						break;
					case 4:
						RMartix[i, j].Fill = new SolidColorBrush ( Colors.Red );
						break;
					}
				}
			}
		} ) );


	}

	///绘制矩阵
	private void drawMartix ( ) {
		//this.Dispatcher.Invoke ( DispatcherPriority.Normal, (ThreadStart)delegate {

		exitBlocks.Content="现有方块数：" + RectArray.Count ( ).ToString ( ) ;
		//打印整个矩阵
		for (int i = 0; i < 100; i++) {
			for (int j = 0; j < 100; j++) {
				switch (Martix[i, j] % 8) {
				case 0:
					RMartix[i, j].Fill = new SolidColorBrush ( Colors.White );
					break;
				case 1:
					RMartix[i, j].Fill = new SolidColorBrush ( Colors.Yellow );
					break;
				case 2:
					RMartix[i, j].Fill = new SolidColorBrush ( Colors.Green );
					break;
				case 3:
					RMartix[i, j].Fill = new SolidColorBrush ( Colors.Blue );
					break;
				case 4:
					RMartix[i, j].Fill = new SolidColorBrush ( Colors.Pink );
					break;
				case 5:
					RMartix[i, j].Fill = new SolidColorBrush ( Colors.Brown );
					break;
				case 6:
					RMartix[i, j].Fill = new SolidColorBrush ( Colors.Orange );
					break;
				case 7:
					RMartix[i, j].Fill = new SolidColorBrush ( Colors.Silver );
					break;
				}
			}

		}

		//    } );

	}

	private  void Start_Click ( object sender, RoutedEventArgs e ) {
		initData ( );
		showLoad.Content = "点击按钮开始演示...";
		cur.Content = "当前方块颜色仅\n用于辨识方块";
		switch (ALGList.SelectedIndex) {
		case 0:
			Thread t = new Thread ( ( ) => {

				Dispatcher.Invoke ( new Action ( ( ) => {
					BuiltRectBy1nd ( 0, 0, 99, 99 );
					drawMartix ( );

				} ) );
			} );
			t.Start ( );
			break;
		case 1:

			Thread t1 = new Thread ( ( ) => {

				Dispatcher.BeginInvoke ( new Action ( ( ) => {
					BuiltRectBy2nd ();
					drawMartix ( );
				} ) );
			} );

			t1.Start ( );
			break;
		}

	}

	private void ListBoxItem_Selected ( object sender, RoutedEventArgs e ) {
		ShowNumOfBlock.IsEnabled= false;
		ChooseNumOfBlock.IsEnabled = false;
		NumOfBlock.IsEnabled = false;
		ShowNumOfBlock.Visibility=Visibility.Hidden;
		ChooseNumOfBlock.Visibility = Visibility.Hidden;
		NumOfBlock.Visibility = Visibility.Hidden;
	}

	private void ListBoxItem_Selected_1 ( object sender, RoutedEventArgs e ) {
		ShowNumOfBlock.IsEnabled = true;
		ChooseNumOfBlock.IsEnabled = true;
		NumOfBlock.IsEnabled =true;
		ShowNumOfBlock.Visibility = Visibility.Visible;
		ChooseNumOfBlock.Visibility = Visibility.Visible;
		NumOfBlock.Visibility = Visibility.Visible;
	}
	private void Window_SizeChanged ( object sender, SizeChangedEventArgs e ) {
		if (RMartix != null) {
			for (int i = 0; i < 100; i++) {
				for (int j = 0; j < 100; j++) {
					RMartix[i, j].Width = PaintCanva.ActualWidth / 100;
					RMartix[i, j].Height = PaintCanva.ActualHeight / 100;
					RMartix[i, j].SetValue ( Canvas.TopProperty, i * RMartix[i, j].Height );
					RMartix[i, j].SetValue ( Canvas.LeftProperty, j * RMartix[i, j].Width );
				}
			}
		}
	}
	Thread bulidThread;

	private void FillBlocks_Click ( object sender, RoutedEventArgs e ) {

		cur.Content ="";
		getAdjacent ( );
		if (bulidThread!=null) {
			bulidThread.Abort ( );
		}
		ThreadStart ts = new ThreadStart ( this.FillWithFourColor );
		bulidThread = new Thread ( ts );
		bulidThread.IsBackground = true;
		bulidThread.Start ( );

		resume.IsEnabled = true;
		stop.IsEnabled = true;
		Start.IsEnabled = false;
		FillBlocks.IsEnabled = false;
	}

	private void resume_Click ( object sender, RoutedEventArgs e ) {
		if (resume.Content.ToString() == "暂停") {
			bulidThread.Suspend ( );

			resume.Content = "恢复";
			stop.IsEnabled = false;
		} else {
			stop.IsEnabled = true;
			bulidThread.Resume ( );

			resume.Content = "暂停";
		}
	}

	private void stop_Click ( object sender, RoutedEventArgs e ) {
		resume.IsEnabled = false;
		stop.IsEnabled = false;
		Start.IsEnabled = true;
		FillBlocks.IsEnabled = true;
		bulidThread.Abort ( );
	}

	private void Window_MouseMove ( object sender, MouseEventArgs e ) {

	}

	private void Window_LayoutUpdated ( object sender, EventArgs e ) {
		if (bulidThread != null && bulidThread.ThreadState != ThreadState.Stopped) {

		} else {
			resume.IsEnabled = false;
			stop.IsEnabled = false;
			Start.IsEnabled = true;
			FillBlocks.IsEnabled =true;
		}
	}
}
}

